/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jmodcog2.map.spheregen;

import com.amd.aparapi.Kernel;
import jmodcog2.util.WeightGen;

/**
 *
 * @author Mitch
 */
public class NSphere extends Kernel {

    private float radius;
    private float[] t = new float[]{1};
    private final int num_pts;
    private final int num_dims;
    private final float[] position;
    private final float[] force;
    
    
    public static float[] generateSphereCoords(int num_pts, int num_dims, float rad, float t) {
        NSphere sphere = new NSphere(num_pts, num_dims, rad, t);
        sphere.execute(num_pts, 128);
        return sphere.getPosArray();
    }
    
    private float[] getPosArray() {
        get(position);
        return position;
    }
    
    private NSphere(int num_pts, int num_dims, float radius, float timestep) {
        this.num_dims = num_dims;
        this.num_pts = num_pts;
        position = new float[num_dims * num_pts];
        force = new float[num_dims * num_pts];
        
        this.radius = radius;
        
        for(int i = 0; i < position.length; i++) {
            position[i] = WeightGen.weight_uniform();
        }
        this.setExplicit(true);
        put(position);
        put(force);
    }

    void _normalize_pos(int point) {
        int i = point * num_dims;
        float m = 0;

        m = 1f/sqrt(_magSq_pos(point));
        while (i > point * num_dims) {
            i -= 1;
            position[i] = radius * position[i] * m;
        }
    }
    
//    void _normalize_force(int point) {
//        int i = point * num_dims;
//        float m = 0;
//
//        m = 1f/sqrt(_magSq_f(point));
//        while (i > point * num_dims) {
//            i -= 1;
//            force[i] = force[i] * m;
//        }
//    }
//
//    void _step(float t, int point) {
//        _normalize_force(point);
//        _force(t, point);
//        _normalize_pos(point);
//        _repel_all(point);
//    }
    
    void _force(float t, int point) {
        int i = 0;
        int i0 = point * num_dims;
        while (i < num_dims) {
            position[i0 + i] += force[i0 + i] * t;
            i += 1;
        }
    }
    
    void _repel_all(int point) {
        int i = 0;
        while (i < num_pts) {
            _repel(point, i);
            i += 1;
        }
    }

    void _repel(int p0, int p1) {
        if (p0 != p1) {
            float d = 0;
            int i = 0, i0 = 0, i1 = 0;
            i0 = p0 * num_dims;
            i1 = p1 * num_dims;
            //
            d = 1f / (1f + _distSq(p0, p1));

            //
            i = 0;
            while (i < num_dims) {
                force[i0 + i] += (position[i0 + i] - position[i1 + i]) * d;
            }
        }
    }

    float _magSq_pos(int point) {
        float sum = 0;
        float v = 0;
        int i = point * num_dims;
        while (i < (point + 1) * num_dims) {
            v = position[i];
            sum += v * v;
        }
        return sum;
    }
    
    float _magSq_f(int point) {
        float sum = 0;
        float v = 0;
        int i = point * num_dims;
        while (i < (point + 1) * num_dims) {
            v = force[i];
            sum += v * v;
        }
        return sum;
    }

    float _distSq(int p0, int p1) {
        float sum = 0;
        int i0 = p0 * num_dims;
        int i1 = p1 * num_dims;
        int i = 0;
        while (i < num_dims) {
            float v = position[i0 + i] - position[i1 + i];
            sum += v * v;
        }
        return sum;
    }

    @Override
    public void run() {
        int f = this.getPassId()%3;
        int i = getGlobalId();
        if(f == 0) {
            
        }
    }
}
